// created by noellynch
// May 6, 2009

package com.sceneworker.editors.rotationeditor;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.myjavautils.swing.MigLayoutUtils;
import com.myjavautils.swing.SwingComponentFactory;

/**
 * Takes a quaternion and represents it as 3 eulerish angles (well angles about the 3 intertial cartesian axes). They are applied in the order YZX. The supplied quaternion can be a copy or the actual quaternion itself.
 * @author noellynch
 *
 */
public class EulerQuaternionEditorPanel extends JPanel {

	private		Quaternion		mcl_rot;
	
	private		JTextField		mcl_xRot;
	private		JTextField		mcl_yRot;
	private		JTextField		mcl_zRot;
	
	private		float			mfa_angles[] = new float[3];
	
	private		boolean			mb_copy;
	
	private		IRotationModifiedCallback		mcl_listener;
	
	public	EulerQuaternionEditorPanel(Quaternion cl_rot, boolean b_asCopy, IRotationModifiedCallback cl_listener) {
		mb_copy = b_asCopy;
		mcl_listener = cl_listener;
		
		initQuaternion(cl_rot);
		
		MigLayoutUtils.asMigLayout(this);
		
		mcl_xRot = MigLayoutUtils.numberText(this, "X", 0, true);
		mcl_yRot = MigLayoutUtils.numberText(this, "Y", 0, true);
		mcl_zRot = MigLayoutUtils.numberText(this, "Z", 0, true);
		
		ActionListener		lcl_action = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyRotations();
			}
		};
		
		KeyListener			lcl_key = new KeyListener() {
			public void keyPressed(KeyEvent e) {
				applyRotations();
			}

			public void keyReleased(KeyEvent e) {
				applyRotations();
			}

			public void keyTyped(KeyEvent e) {
				applyRotations();
			}
		};
		
		mcl_xRot.addActionListener(lcl_action);
		mcl_yRot.addActionListener(lcl_action);
		mcl_zRot.addActionListener(lcl_action);
		
		mcl_xRot.addKeyListener(lcl_key);
		mcl_yRot.addKeyListener(lcl_key);
		mcl_zRot.addKeyListener(lcl_key);
		
		updateTextFields();
		
		final	EulerQuaternionEditorPanel	lcl_this = this;
		
		JButton		lcl_reset = SwingComponentFactory.makeAButton("Reset");
		lcl_reset.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				mcl_xRot.setText("0.0");
				mcl_yRot.setText("0.0");
				mcl_zRot.setText("0.0");
				
				mcl_rot.set(0, 0, 0, 1);
				
				if(mcl_listener != null) {
					mcl_listener.rotationModifed(lcl_this);
				}
			}
		});
		
		MigLayoutUtils.makeRightAlignedButtonBar(this, lcl_reset);
	}
	
	private	void	initQuaternion(Quaternion cl_rot) {
		if(mb_copy) {
			mcl_rot = new Quaternion(cl_rot);
		} else {
			mcl_rot = cl_rot;
		}
	}
	
	public	Quaternion	getQuaternion() {
		return mcl_rot;
	}
	
	public	void	setQuaternion(Quaternion cl_rot) {
		initQuaternion(cl_rot);
		updateTextFields();
	}
	
	private		void	updateTextFields() {
		mcl_rot.toAngles(mfa_angles);
		mcl_xRot.setText(String.format("%.2f", FastMath.RAD_TO_DEG * mfa_angles[0]));
		mcl_yRot.setText(String.format("%.2f", FastMath.RAD_TO_DEG * mfa_angles[1]));
		mcl_zRot.setText(String.format("%.2f", FastMath.RAD_TO_DEG * mfa_angles[2]));
	}
	
	private	Quaternion	applyRotations() {
		Quaternion		lcl_xRot = new Quaternion();
		Quaternion		lcl_yRot = new Quaternion();
		Quaternion		lcl_zRot = new Quaternion();
		
		Quaternion		lcl_rot = new Quaternion();
		
		try {
			float		lf_xRot = Float.parseFloat(mcl_xRot.getText()) * FastMath.DEG_TO_RAD;
			float		lf_yRot = Float.parseFloat(mcl_yRot.getText()) * FastMath.DEG_TO_RAD;
			float		lf_zRot = Float.parseFloat(mcl_zRot.getText()) * FastMath.DEG_TO_RAD;
			
			lcl_xRot.fromAngleAxis(lf_xRot, Vector3f.UNIT_X);
			lcl_yRot.fromAngleAxis(lf_yRot, Vector3f.UNIT_Y);
			lcl_zRot.fromAngleAxis(lf_zRot, Vector3f.UNIT_Z);
			
			lcl_rot.multLocal(lcl_yRot);
			lcl_rot.multLocal(lcl_zRot);
			lcl_rot.multLocal(lcl_xRot);
			
			mcl_rot.set(lcl_rot);
			
			if(mcl_listener != null) {
				mcl_listener.rotationModifed(this);
			}
			
			return lcl_rot;
		} catch (NumberFormatException e) {
			return mcl_rot;
		}
	}
	
	public	interface	IRotationModifiedCallback {
		void	rotationModifed(EulerQuaternionEditorPanel cl_rot);
	}
}
